﻿// Type: System.ServiceModel.DomainServices.Client.EntityContainer
// Assembly: System.ServiceModel.DomainServices.Client, Version=2.0.5.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35
// Assembly location: C:\Program Files (x86)\Microsoft SDKs\RIA Services\v1.0\Libraries\Silverlight\System.ServiceModel.DomainServices.Client.dll

using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Globalization;
using System.Linq;
using System.Threading;

namespace System.ServiceModel.DomainServices.Client
{
  public abstract class EntityContainer : IRevertibleChangeTracking, IChangeTracking, INotifyPropertyChanged
  {
    private IDictionary<Type, EntitySet> _entitySets;
    private IDictionary<Type, EntitySet> _referencedEntitySets;
    private IDictionary<string, Type> _entityTypeMap;
    private int _dirtySetCount;
    private IDictionary<Type, Type> _entityRootTypes;
    private ValidationContext _validationContext;
    private PropertyChangedEventHandler PropertyChanged;

    public bool HasChanges
    {
      get
      {
        return Enumerable.Any<KeyValuePair<Type, EntitySet>>((IEnumerable<KeyValuePair<Type, EntitySet>>) this._entitySets, (Func<KeyValuePair<Type, EntitySet>, bool>) (p => p.Value.IsChanged));
      }
    }

    public IEnumerable<EntitySet> EntitySets
    {
      get
      {
        foreach (EntitySet entitySet in (IEnumerable<EntitySet>) this._entitySets.Values)
          yield return entitySet;
      }
    }

    internal ValidationContext ValidationContext
    {
      get
      {
        return this._validationContext;
      }
      set
      {
        this._validationContext = value;
      }
    }

    bool IChangeTracking.IsChanged
    {
      get
      {
        return this.HasChanges;
      }
    }

    public event PropertyChangedEventHandler PropertyChanged
    {
      add
      {
        PropertyChangedEventHandler changedEventHandler = this.PropertyChanged;
        PropertyChangedEventHandler comparand;
        do
        {
          comparand = changedEventHandler;
          changedEventHandler = Interlocked.CompareExchange<PropertyChangedEventHandler>(ref this.PropertyChanged, comparand + value, comparand);
        }
        while (changedEventHandler != comparand);
      }
      remove
      {
        PropertyChangedEventHandler changedEventHandler = this.PropertyChanged;
        PropertyChangedEventHandler comparand;
        do
        {
          comparand = changedEventHandler;
          changedEventHandler = Interlocked.CompareExchange<PropertyChangedEventHandler>(ref this.PropertyChanged, comparand - value, comparand);
        }
        while (changedEventHandler != comparand);
      }
    }

    protected EntityContainer()
    {
      this._entitySets = (IDictionary<Type, EntitySet>) new Dictionary<Type, EntitySet>();
      this._referencedEntitySets = (IDictionary<Type, EntitySet>) new Dictionary<Type, EntitySet>();
      this._entityTypeMap = (IDictionary<string, Type>) new Dictionary<string, Type>();
      this._entityRootTypes = (IDictionary<Type, Type>) new Dictionary<Type, Type>();
    }

    internal void CheckCrossContainer(Entity entity)
    {
      EntityContainer entityContainer = entity.LastSet != null ? entity.LastSet.EntityContainer : (EntityContainer) null;
      if (entityContainer == null || entityContainer == this)
        return;
      throw new InvalidOperationException(string.Format((IFormatProvider) CultureInfo.CurrentCulture, Resource.EntityContainer_CrossContainerAttach, new object[1]
      {
        (object) entity
      }));
    }

    public void AddReference(EntitySet entitySet)
    {
      if (entitySet == null)
        throw new ArgumentNullException("entitySet");
      Type entityType = entitySet.EntityType;
      if (this._entitySets.ContainsKey(entityType) || this._referencedEntitySets.ContainsKey(entityType))
        throw new ArgumentException(string.Format((IFormatProvider) CultureInfo.InvariantCulture, Resource.EntityContainer_EntitySetAlreadyExists, new object[1]
        {
          (object) entityType
        }));
      else
        this._referencedEntitySets.Add(entityType, entitySet);
    }

    public void Clear()
    {
      foreach (KeyValuePair<Type, EntitySet> keyValuePair in (IEnumerable<KeyValuePair<Type, EntitySet>>) this._entitySets)
        keyValuePair.Value.Clear();
    }

    protected void CreateEntitySet<TEntity>() where TEntity : Entity
    {
      this.CreateEntitySet<TEntity>(EntitySetOperations.None);
    }

    protected void CreateEntitySet<TEntity>(EntitySetOperations supportedOperations) where TEntity : Entity
    {
      this.AddEntitySet((EntitySet) new EntitySet<TEntity>(), supportedOperations);
    }

    internal void AddEntitySet(EntitySet set, EntitySetOperations supportedOperations)
    {
      set.Initialize(this, supportedOperations);
      this._entitySets[set.EntityType] = set;
      this._entityTypeMap[set.EntityType.Name] = set.EntityType;
    }

    internal void SetPropertyChanged(EntitySet entitySet, string propertyName)
    {
      if (string.CompareOrdinal(propertyName, "HasChanges") != 0)
        return;
      if (entitySet.HasChanges)
      {
        if (this._dirtySetCount++ != 0)
          return;
        this.RaisePropertyChanged("HasChanges");
      }
      else
      {
        if (this._dirtySetCount <= 0 || --this._dirtySetCount != 0)
          return;
        this.RaisePropertyChanged("HasChanges");
      }
    }

    public EntitySet<TEntity> GetEntitySet<TEntity>() where TEntity : Entity
    {
      EntitySet<TEntity> entitySet = this.GetEntitySet(typeof (TEntity)) as EntitySet<TEntity>;
      if (entitySet != null)
        return entitySet;
      throw new InvalidOperationException(string.Format((IFormatProvider) CultureInfo.CurrentCulture, Resource.EntityContainer_CannotRetrieveEntitySetForDerivedEntity, new object[2]
      {
        (object) typeof (TEntity).Name,
        (object) this.GetRootEntityType(typeof (TEntity)).Name
      }));
    }

    public EntitySet GetEntitySet(Type entityType)
    {
      EntitySet entitySet;
      if (this.TryGetEntitySet(entityType, out entitySet))
        return entitySet;
      throw new InvalidOperationException(string.Format((IFormatProvider) CultureInfo.CurrentCulture, Resource.EntityContainerDoesntContainEntityType, new object[1]
      {
        (object) entityType
      }));
    }

    public bool TryGetEntitySet(Type entityType, out EntitySet entitySet)
    {
      Type rootEntityType = this.GetRootEntityType(entityType);
      if (rootEntityType != null && (this._entitySets.TryGetValue(rootEntityType, out entitySet) || this._referencedEntitySets.TryGetValue(rootEntityType, out entitySet)))
        return true;
      entitySet = (EntitySet) null;
      return false;
    }

    public EntityChangeSet GetChanges()
    {
      List<Entity> list1 = new List<Entity>();
      List<Entity> list2 = new List<Entity>();
      List<Entity> list3 = new List<Entity>();
      foreach (KeyValuePair<Type, EntitySet> keyValuePair in (IEnumerable<KeyValuePair<Type, EntitySet>>) this._entitySets)
      {
        foreach (Entity entity in keyValuePair.Value.InterestingEntities)
        {
          if (entity.EntityState == EntityState.New)
            list1.Add(entity);
          else if (entity.EntityState == EntityState.Modified)
            list2.Add(entity);
          else if (entity.EntityState == EntityState.Deleted)
            list3.Add(entity);
        }
      }
      return new EntityChangeSet(list1.AsReadOnly(), list2.AsReadOnly(), list3.AsReadOnly());
    }

    internal bool HasChildChanges(Entity entity)
    {
      foreach (Type entityType in entity.MetaType.ChildTypes)
      {
        foreach (Entity entity1 in this.GetEntitySet(entityType).InterestingEntities)
        {
          if (entity1.Parent == entity && entity1.EntityState != EntityState.Unmodified)
            return true;
        }
      }
      return false;
    }

    internal void CompleteChildChanges(Entity entity, bool acceptChanges)
    {
      foreach (Type entityType in entity.MetaType.ChildTypes)
      {
        foreach (Entity entity1 in Enumerable.ToArray<Entity>((IEnumerable<Entity>) this.GetEntitySet(entityType).InterestingEntities))
        {
          if (entity1.Parent == entity && entity1.EntityState != EntityState.Unmodified)
          {
            if (acceptChanges)
              entity1.AcceptChanges();
            else
              entity1.RejectChanges();
          }
        }
      }
    }

    protected void AcceptChanges()
    {
      foreach (KeyValuePair<Type, EntitySet> keyValuePair in (IEnumerable<KeyValuePair<Type, EntitySet>>) this._entitySets)
        keyValuePair.Value.AcceptChanges();
    }

    protected void RejectChanges()
    {
      foreach (KeyValuePair<Type, EntitySet> keyValuePair in (IEnumerable<KeyValuePair<Type, EntitySet>>) this._entitySets)
        keyValuePair.Value.RejectChanges();
    }

    public IEnumerable LoadEntities(IEnumerable entities)
    {
      return this.LoadEntities(entities, LoadBehavior.KeepCurrent);
    }

    public IEnumerable LoadEntities(IEnumerable entities, LoadBehavior loadBehavior)
    {
      if (entities == null)
        throw new ArgumentNullException("entities");
      List<Entity> list = new List<Entity>();
      foreach (IGrouping<EntitySet, Entity> grouping in Enumerable.GroupBy<Entity, EntitySet>(Enumerable.Cast<Entity>(entities), (Func<Entity, EntitySet>) (p => this.GetEntitySet(p.GetType()))))
      {
        EntitySet key = grouping.Key;
        list.AddRange(key.LoadEntities((IEnumerable<Entity>) grouping, loadBehavior));
      }
      return (IEnumerable) list;
    }

    internal Type ResolveEntityType(string typeName)
    {
      Type type = (Type) null;
      this._entityTypeMap.TryGetValue(typeName, out type);
      return type;
    }

    private Type GetRootEntityType(Type entityType)
    {
      Type type = (Type) null;
      if (!this._entityRootTypes.TryGetValue(entityType, out type))
      {
        for (Type key = entityType; key != null; key = key.BaseType)
        {
          if (this._entitySets.ContainsKey(key) || this._referencedEntitySets.ContainsKey(key))
          {
            type = key;
            this._entityRootTypes[entityType] = type;
            break;
          }
        }
      }
      return type;
    }

    void IRevertibleChangeTracking.RejectChanges()
    {
      this.RejectChanges();
    }

    void IChangeTracking.AcceptChanges()
    {
      this.AcceptChanges();
    }

    protected void RaisePropertyChanged(string propertyName)
    {
      if (this.PropertyChanged == null)
        return;
      this.PropertyChanged((object) this, new PropertyChangedEventArgs(propertyName));
    }
  }
}
